(define-library (oaxaca wfs)

  (export wfs-initialized?
          wfs-command
          wfs-idle!
          wfs-pixel-clock-frequency
          wfs-set-pixel-clock-frequency!
          wfs-window
          wfs-set-window!
          wfs-min-frame-frequency
          wfs-max-frame-frequency
          wfs-frame-frequency
          wfs-set-frame-frequency!
          wfs-ao-gain
          wfs-set-ao-gain!
          wfs-expose!
          wfs-dark!
          wfs-ao!)

  (import (scheme base)
          (scheme char)
          (scheme time)
          (scheme write))

  (import (oaxaca file)
          (prefix (oaxaca foreign) foreign:)
          (oaxaca log)
          (oaxaca thread)
          (oaxaca wfc))

  (begin

    (define (wfs-initialized?)
      (not (zero? (foreign:wfs-initialized))))

    (define (check-wfs-initialized)
      (unless (wfs-initialized?)
        (error "the wfs is not initialized."))
      (values))

    (define (wfs-idle?)
      (eqv? #\I (foreign:wfs-command)))

    (define (check-wfs-idle)
      (unless (wfs-idle?)
        (error "the wfs is not idle."))
      (values))

    (define (check-wfs-initialized-and-idle)
      (check-wfs-initialized)
      (check-wfs-idle))

    (define (wfs-pixel-clock-frequency)
      (foreign:wfs-pixel-clock-frequency))

    (define (wfs-set-pixel-clock-frequency! pixel-clock-frequency)
      (check-wfs-initialized-and-idle)
      (foreign:wfs-set-pixel-clock-frequency! (inexact pixel-clock-frequency))
      (wfs-command! #\c #\I)
      (values))

    (define (wfs-window)
      (values (foreign:wfs-window-sx)
              (foreign:wfs-window-sy)
              (foreign:wfs-window-nx)
              (foreign:wfs-window-ny)))

    (define (wfs-set-window! sx sy nx ny)
      (check-wfs-initialized-and-idle)
      (foreign:wfs-set-window-sx! sx)
      (foreign:wfs-set-window-sy! sy)
      (foreign:wfs-set-window-nx! nx)
      (foreign:wfs-set-window-ny! ny)
      (wfs-command! #\c #\I)
      (values))

    (define (wfs-min-frame-frequency)
      (foreign:wfs-min-frame-frequency))

    (define (wfs-max-frame-frequency)
      (foreign:wfs-max-frame-frequency))

    (define (wfs-frame-frequency)
      (foreign:wfs-frame-frequency))

    (define (wfs-set-frame-frequency! frame-frequency)
      (check-wfs-initialized-and-idle)
      (foreign:wfs-set-frame-frequency! (inexact frame-frequency))
      (wfs-command! #\c #\I)
      (values))

    (define (wfs-ao-gain)
      (foreign:wfs-ao-gain))

    (define (wfs-set-ao-gain! ao-gain)
      (check-wfs-initialized)
      (foreign:wfs-set-ao-gain! (inexact ao-gain))
      (values))

    (define (wfs-idle!)
      (check-wfs-initialized)
      (wfs-command! #\i #\I)
      (values))

    (define (wfs-expose! exposure-time fits-file-path)
      (check-wfs-initialized-and-idle)
      (foreign:wfs-set-exposure-time! (inexact exposure-time))
      (wfs-command! #\e #\I)
      (let ((wfs-fits-file-path (make-path (dot-oaxaca-directory-path)
                                           "wfs"
                                           "exposure.fits")))
        (move-file wfs-fits-file-path fits-file-path))
      (values))

    (define (wfs-dark! exposure-time fits-file-path)
      (check-wfs-initialized-and-idle)
      (foreign:wfs-set-exposure-time! (inexact exposure-time))
      (wfs-command! #\d #\I)
      (let ((wfs-fits-file-path (make-path (dot-oaxaca-directory-path)
                                           "wfs"
                                           "exposure.fits")))
        (move-file wfs-fits-file-path fits-file-path))
      (values))

    (define (wfs-ao! exposure-time)
      (check-wfs-initialized-and-idle)
      (foreign:wfs-set-exposure-time! exposure-time)
      (wfc-set-modal! #t)
      (foreign:wfs-set-command! #\a)
      (values))

    (define (wfs-command)
      (foreign:wfs-command))

    (define (wfs-command! command acknowledgement)
      (check-wfs-initialized)
      (foreign:wfs-set-command! command)
      (thread-wait-until!
       (lambda ()
         (char=? (foreign:wfs-command) acknowledgement)))
      (values))))
